package zelix.hack.hacks;

import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.monster.EntityMob;
import net.minecraft.entity.passive.EntityAnimal;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.network.play.client.CPacketPlayer;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent;
import zelix.hack.Hack;
import zelix.hack.HackCategory;
import zelix.utils.AStarCustomPathFinder;
import zelix.utils.TimerUtils;
import zelix.utils.ValidUtils;
import zelix.utils.Wrapper;
import zelix.value.BooleanValue;
import zelix.value.NumberValue;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class TpAura extends Hack {
	private TimerUtils cps = new TimerUtils();
	public static TimerUtils timer = new TimerUtils();
	private ArrayList<Vec3d> path = new ArrayList<>();
	private List<Vec3d>[] test = new ArrayList[50];
	public int ticks;
	// settings
	public NumberValue delay;
	public NumberValue range;
	public BooleanValue players;
	public BooleanValue mobs;
	public BooleanValue atkinv;
	public BooleanValue animals;
	public NumberValue maxtarget;
	public NumberValue dashDistance;

	public TpAura() {
		super("TpAura", HackCategory.COMBAT);
		delay = new NumberValue("Delay", 4.0D, 0.0D, 20.0D);
		range = new NumberValue("Range", 10.0, 10.0, 100.0);
		players = new BooleanValue("Players", true);
		atkinv = new BooleanValue("Invisible", true);
		mobs = new BooleanValue("Mobs", true);
		animals = new BooleanValue("Animals", false);
		maxtarget = new NumberValue("MaxTarget", 3.0, 1.0, 10.0);
		dashDistance = new NumberValue("DashDistance", 5.0, 2.0, 10.0);

		this.addValue(players, animals,mobs, atkinv, delay, dashDistance, maxtarget, range);
	}

	@Override
	public void onClientTick(ClientTickEvent event) {
		this.ticks += 1;

		if (this.cps.hasReached(delay.getValue().intValue() * 100)) {

			if (getTargets().size() > 0) {
				test = new ArrayList[50];

				for (int i = 0; i < (getTargets().size() > maxtarget.getValue().intValue()
						? maxtarget.getValue().intValue()
						: getTargets().size()); i++) {
					EntityLivingBase T = getTargets().get(i);
					Vec3d topFrom = new Vec3d(Wrapper.INSTANCE.player().posX, Wrapper.INSTANCE.player().posY,
							Wrapper.INSTANCE.player().posZ);
					Vec3d to = new Vec3d(T.posX, T.posY, T.posZ);
					path = computePath(topFrom, to);
					test[i] = path;
					if (ValidUtils.isTeam(T)) {
						for (Vec3d pathElm : path) {
							Wrapper.INSTANCE.sendPacket(
									(new CPacketPlayer.Position(pathElm.x, pathElm.y + 0.1451D, pathElm.z, true)));
						}

						Wrapper.INSTANCE.player().swingArm(EnumHand.MAIN_HAND);

						Wrapper.INSTANCE.controller().attackEntity(Wrapper.INSTANCE.player(), T);

						Collections.reverse(path);
						cps.reset();
						for (Vec3d pathElm : path) {
							Wrapper.INSTANCE.sendPacket(
									new CPacketPlayer.Position(pathElm.x, pathElm.y, pathElm.z + 0.1451D, true));
						}

					}
				}
			}

		}

	}

	public List<EntityLivingBase> getTargets() {
		List<EntityLivingBase> targets = new ArrayList<>();

		for (Object o : Wrapper.INSTANCE.world().getLoadedEntityList()) {
			if (o instanceof EntityLivingBase) {

				EntityLivingBase entity = (EntityLivingBase) o;
				if (entity != null && !entity.isDead && !Wrapper.INSTANCE.player().isDead
						&& (entity instanceof EntityLivingBase) && !(entity == Wrapper.INSTANCE.player())
						&& Wrapper.INSTANCE.player().getDistance(entity) <= range.getValue()
						&& !entity.isPlayerSleeping()) {

					if (entity instanceof EntityPlayer && players.getValue() && !entity.isInvisible()) {
						targets.add(entity);

					} else if (entity instanceof EntityPlayer && players.getValue() && entity.isInvisible()
							&& !atkinv.getValue()) {
						targets.remove(entity);
					} else if (entity instanceof EntityPlayer && players.getValue() && entity.isInvisible()
							&& atkinv.getValue()) {
						targets.add(entity);
					}

					if (entity instanceof EntityAnimal && animals.getValue() && !entity.isInvisible()) {
						targets.add(entity);

					} else if (entity instanceof EntityAnimal && animals.getValue() && entity.isInvisible()
							&& !atkinv.getValue()) {

						targets.remove(entity);
					} else if (entity instanceof EntityAnimal && animals.getValue() && entity.isInvisible()
							&& atkinv.getValue()) {
						targets.add(entity);

					}

					if (entity instanceof EntityMob && mobs.getValue() && !entity.isInvisible()) {
						targets.add(entity);

					} else if (entity instanceof EntityMob && mobs.getValue() && entity.isInvisible()
							&& !atkinv.getValue()) {

						targets.remove(entity);
					} else if (entity instanceof EntityMob && mobs.getValue() && entity.isInvisible()
							&& atkinv.getValue()) {
						targets.add(entity);

					}

				}
			}
		}

		targets.sort((o1, o2) -> (int) (o1.getDistance(Wrapper.INSTANCE.player()) * 1000
				- o2.getDistance(Wrapper.INSTANCE.player()) * 1000));
		return targets;
	}

	private ArrayList<Vec3d> computePath(Vec3d topFrom, Vec3d to) {
		AStarCustomPathFinder pathfinder = new AStarCustomPathFinder(topFrom, to);
		pathfinder.compute();
		int i = 0;
		Vec3d lastLoc = null;
		Vec3d lastDashLoc = null;
		ArrayList<Vec3d> path = new ArrayList<Vec3d>();
		ArrayList<Vec3d> pathFinderPath = pathfinder.getPath();

		for (Vec3d pathElm : pathFinderPath) {
			if (i == 0 || i == pathFinderPath.size() - 1) {
				if (lastLoc != null) {
					path.add(lastLoc.addVector(0.5, 0, 0.5));
				}

				path.add(pathElm.addVector(0.5, 0, 0.5));
				lastDashLoc = pathElm;
			} else {
				boolean canContinue = true;

				if (pathElm.squareDistanceTo(lastDashLoc) > dashDistance.getValue() * dashDistance.getValue()) {
					canContinue = false;
				} else {
					double smallX = Math.min(lastDashLoc.x, pathElm.x);
					double smallY = Math.min(lastDashLoc.y, pathElm.y);
					double smallZ = Math.min(lastDashLoc.z, pathElm.z);
					double bigX = Math.max(lastDashLoc.x, pathElm.x);
					double bigY = Math.max(lastDashLoc.y, pathElm.y);
					double bigZ = Math.max(lastDashLoc.z, pathElm.z);
					cordsLoop:

					for (int x = (int) smallX; x <= bigX; x++) {
						for (int y = (int) smallY; y <= bigY; y++) {
							for (int z = (int) smallZ; z <= bigZ; z++) {
								if (!AStarCustomPathFinder.checkPositionValidity(x, y, z, false)) {
									canContinue = false;
									break cordsLoop;
								}
							}
						}
					}
				}

				if (!canContinue) {
					path.add(lastLoc.addVector(0.5, 0, 0.5));
					lastDashLoc = lastLoc;
				}
			}

			lastLoc = pathElm;
			i++;
		}

		return path;
	}
}
